import tkinter as tk
from tkinter import ttk, messagebox
import threading
import time
import pyautogui
import pytesseract
from PIL import Image, ImageGrab
import keyboard
import requests
import json
import os
import random
import hashlib
from translate import Translator
import cv2
import numpy as np
from functools import lru_cache

class ScreenTranslator:
    def __init__(self):
        # 创建主窗口
        self.root = tk.Tk()
        self.root.title("屏幕翻译工具")
        self.root.geometry("400x600")  
        self.root.resizable(False, False)
        
        # 初始化所有变量
        self.init_variables()
        
        # 设置pytesseract路径和OCR配置
        pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
        
        # 设置窗口置顶
        self.root.wm_attributes('-topmost', True)
        
        # 设置窗口样式
        self.style = ttk.Style()
        self.style.configure('TButton', padding=6, font=('微软雅黑', 10))
        self.style.configure('TRadiobutton', font=('微软雅黑', 10))
        self.style.configure('TLabel', font=('微软雅黑', 10))
        self.style.configure('TCheckbutton', font=('微软雅黑', 10))
        self.style.configure('TLabelframe', font=('微软雅黑', 10))
        self.style.configure('TLabelframe.Label', font=('微软雅黑', 10))
        
        # 创建主框架
        main_frame = ttk.Frame(self.root, padding="20 15")  
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 创建标题
        title_label = ttk.Label(main_frame, text="屏幕区域翻译工具", 
                               font=('微软雅黑', 16, 'bold'))  
        title_label.pack(pady=(0, 15))  

        # 创建说明文本框架
        desc_frame = ttk.LabelFrame(main_frame, text="使用说明", padding="10 5")  
        desc_frame.pack(fill='x', pady=(0, 10))  
        
        # 创建说明文本
        instructions = [
            "1. 点击开始截图按钮",
            "2. 选择区域",
            "3. 选择区域后自动开始翻译",
            "4. 拖动翻译窗口边缘可调整大小",
            "5. 取消实时翻译后，使用Ctrl+Shift+/手动触发翻译"
        ]
        
        for instruction in instructions:
            ttk.Label(desc_frame, text=instruction, 
                     justify=tk.LEFT).pack(anchor='w', pady=1)  
        
        # 创建源语言提示框架
        source_lang_frame = ttk.LabelFrame(main_frame, text="源语言", padding="10 5")
        source_lang_frame.pack(fill='x', pady=(0, 10))
        
        # 创建源语言提示
        ttk.Label(source_lang_frame, text="英语", 
                padding="10 3").pack(anchor='center')
        
        # 创建翻译语言框架
        target_lang_frame = ttk.LabelFrame(main_frame, text="翻译语言", padding="10 5")
        target_lang_frame.pack(fill='x', pady=(0, 10))
        
        # 创建目标语言显示
        ttk.Label(target_lang_frame, text="中文", 
                padding="10 3").pack(anchor='center')
        
        # 创建实时翻译选项框架
        realtime_frame = ttk.LabelFrame(main_frame, text="翻译模式", padding="10 5")
        realtime_frame.pack(fill='x', pady=(0, 10))
        
        # 创建实时翻译选项，默认开启
        self.realtime_active = True  # 默认开启实时翻译
        realtime_check = ttk.Checkbutton(realtime_frame, 
                                     text="实时翻译模式",
                                     variable=self.realtime_var,
                                     command=self.toggle_realtime)
        realtime_check.pack(anchor='center', pady=3)
        
        # 创建开始按钮
        self.start_button = ttk.Button(main_frame, 
                                   text="开始截图",
                                   command=self.start_capture,
                                   style='TButton',
                                   width=20)  
        self.start_button.pack(pady=(5, 0))

        # 创建菜单栏
        self.create_menu()
        
        # 注册手动翻译快捷键
        self.register_hotkey()

    def init_variables(self):
        """初始化所有变量"""
        # 监控相关变量
        self.monitoring = False
        self.realtime_active = False
        self.last_text = ""
        self.hotkey_registered = False
        self.monitor_thread = None
        
        # 翻译API配置
        self.translation_service = 'mymemory'  # 默认使用MyMemory
        self.translation_error_count = 0
        self.max_error_count = 3  # 连续错误次数达到此值时切换服务
        self.baidu_appid = ""  # 百度翻译API的APPID
        self.baidu_secretkey = ""  # 百度翻译API的密钥
        
        # 翻译设置变量
        self.lang_var = tk.StringVar(value='zh')  # 固定为中文
        self.realtime_var = tk.BooleanVar(value=True)
        
        # 菜单相关变量
        self.service_var = tk.StringVar(value=self.translation_service)
        self.psm_var = tk.IntVar(value=6)
        self.autocopy_var = tk.BooleanVar(value=False)
        self.topmost_var = tk.BooleanVar(value=True)  # 默认置顶
        self.interval_var = tk.StringVar(value='1.0')  # 默认1秒
        
        # 监控区域变量
        self.monitor_region = None
        
        # 选择框窗口
        self.region_window = None
        # 翻译结果窗口
        self.result_window = None
        
        # 缓存相关
        self.translation_cache = {}
        self.max_cache_size = 100
        self.last_ocr_hash = None
        self.last_translation_time = 0
        self.min_translation_interval = 1.0
        
        # OCR配置
        self.custom_config = r'--oem 1 --psm 6'
        
        # 配置文件路径
        self.config_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'config.json')
        
        # 加载配置
        self.load_config()
        
    def load_config(self):
        """加载配置文件"""
        default_config = {
            'baidu_appid': '',
            'baidu_secretkey': '',
            'translation_service': 'mymemory',
            'topmost': True,
            'autocopy': False,
            'psm': 6,
            'interval': 1.0
        }
        
        try:
            if os.path.exists(self.config_file):
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    config = json.load(f)
                    self.baidu_appid = config.get('baidu_appid', '')
                    self.baidu_secretkey = config.get('baidu_secretkey', '')
                    self.translation_service = config.get('translation_service', 'mymemory')
                    self.topmost_var.set(config.get('topmost', True))
                    self.autocopy_var.set(config.get('autocopy', False))
                    self.psm_var.set(config.get('psm', 6))
                    self.interval_var.set(str(config.get('interval', 1.0)))
                    self.min_translation_interval = float(self.interval_var.get())
            else:
                self.baidu_appid = default_config['baidu_appid']
                self.baidu_secretkey = default_config['baidu_secretkey']
                self.translation_service = default_config['translation_service']
                self.topmost_var.set(default_config['topmost'])
                self.autocopy_var.set(default_config['autocopy'])
                self.psm_var.set(default_config['psm'])
                self.interval_var.set(str(default_config['interval']))
                self.min_translation_interval = default_config['interval']
        except Exception as e:
            print(f"加载配置文件失败: {e}")
            self.baidu_appid = default_config['baidu_appid']
            self.baidu_secretkey = default_config['baidu_secretkey']
            self.translation_service = default_config['translation_service']
            self.topmost_var.set(default_config['topmost'])
            self.autocopy_var.set(default_config['autocopy'])
            self.psm_var.set(default_config['psm'])
            self.interval_var.set(str(default_config['interval']))
            self.min_translation_interval = default_config['interval']

    def save_config(self):
        """保存配置到文件"""
        config = {
            'baidu_appid': self.baidu_appid,
            'baidu_secretkey': self.baidu_secretkey,
            'translation_service': self.translation_service,
            'topmost': self.topmost_var.get(),
            'autocopy': self.autocopy_var.get(),
            'psm': self.psm_var.get(),
            'interval': float(self.interval_var.get())
        }
        
        try:
            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(config, f, ensure_ascii=False, indent=4)
        except Exception as e:
            print(f"保存配置文件失败: {e}")

    def register_hotkey(self):
        """注册快捷键"""
        if not self.hotkey_registered:
            try:
                keyboard.add_hotkey('ctrl+shift+/', self.manual_translate)
                self.hotkey_registered = True
            except Exception as e:
                print(f"注册快捷键失败: {str(e)}")

    def unregister_hotkey(self):
        """注销快捷键"""
        if self.hotkey_registered:
            try:
                keyboard.remove_hotkey('ctrl+shift+/')
                self.hotkey_registered = False
            except Exception as e:
                print(f"注销快捷键失败: {str(e)}")

    def manual_translate(self):
        """手动触发翻译"""
        if self.monitor_region:
            self.translate_region()

    def create_result_window(self, x, y, width):
        # 创建翻译结果窗口
        if self.result_window:
            self.result_window.destroy()
            
        self.result_window = tk.Toplevel(self.root)
        self.result_window.overrideredirect(True)  # 无边框窗口
        self.result_window.attributes('-alpha', 0.9)  # 设置透明度
        self.result_window.attributes('-topmost', True)  # 窗口置顶
        self.result_window.attributes('-toolwindow', True)  # 设置为工具窗口
        
        # 设置窗口背景色
        self.result_window.configure(bg='#2D2D2D')
        
        # 创建主框架
        main_frame = tk.Frame(self.result_window, bg='#2D2D2D')
        main_frame.pack(fill='both', expand=True, padx=4, pady=4)
        
        # 创建译文标签
        self.translated_label = tk.Label(main_frame,
                                       font=('微软雅黑', 11),
                                       fg='#FFFFFF',
                                       bg='#2D2D2D',
                                       justify=tk.LEFT,
                                       anchor='w',
                                       wraplength=width-20)  
        self.translated_label.pack(padx=10, pady=5, fill='both', expand=True)
        
        # 添加大小调整功能
        self.add_resize_handlers()
        
        # 设置初始大小和位置
        self.result_window.geometry(f"{width}x50+{x}+{y}")  

    def update_result_window_size(self):
        if self.result_window and self.translated_label:
            # 获取文本需要的高度
            self.translated_label.update_idletasks()  # 确保标签已更新
            text_height = self.translated_label.winfo_reqheight()
            
            # 添加内边距
            window_height = text_height + 20  # 上下各10像素的内边距
            
            # 设置最小高度
            window_height = max(50, window_height)
            
            # 更新窗口大小
            x = self.result_window.winfo_x()
            y = self.result_window.winfo_y()
            width = self.result_window.winfo_width()
            self.result_window.geometry(f"{width}x{window_height}+{x}+{y}")

    def add_resize_handlers(self):
        # 创建调整大小的区域（边框）
        border_size = 5
        
        def start_resize(event):
            self.start_x = event.x_root
            self.start_y = event.y_root
            self.start_width = self.result_window.winfo_width()
            self.start_height = self.result_window.winfo_height()
            
        def do_resize(event):
            if not hasattr(self, 'start_width'):
                return
                
            dx = event.x_root - self.start_x
            dy = event.y_root - self.start_y
            
            # 根据拖动的边缘调整窗口大小
            new_width = self.start_width
            new_height = self.start_height
            
            if event.widget == right_border:
                new_width += dx
            elif event.widget == bottom_border:
                new_height += dy
            elif event.widget == corner:
                new_width += dx
                new_height += dy
                
            # 限制最小尺寸
            new_width = max(200, new_width)
            new_height = max(100, new_height)
            
            # 更新窗口大小
            self.result_window.geometry(f"{new_width}x{new_height}")
            
            # 更新文本换行宽度
            self.translated_label.configure(wraplength=new_width-20)
            
        # 创建调整大小的边框（使用深色以适应透明背景）
        right_border = tk.Frame(self.result_window, bg='#1A1A1A', cursor='sb_h_double_arrow', width=border_size)
        bottom_border = tk.Frame(self.result_window, bg='#1A1A1A', cursor='sb_v_double_arrow', height=border_size)
        corner = tk.Frame(self.result_window, bg='#1A1A1A', cursor='sizing', width=border_size, height=border_size)
        
        right_border.place(relx=1, rely=0, relheight=1, anchor='ne')
        bottom_border.place(relx=0, rely=1, relwidth=1, anchor='sw')
        corner.place(relx=1, rely=1, anchor='se')
        
        # 绑定事件
        for widget in [right_border, bottom_border, corner]:
            widget.bind('<Button-1>', start_resize)
            widget.bind('<B1-Motion>', do_resize)
        
    def update_result_window_position(self):
        if self.region_window and self.result_window:
            # 获取选择框的位置和大小
            x = self.region_window.winfo_x()
            y = self.region_window.winfo_y()
            width = self.region_window.winfo_width()
            height = self.region_window.winfo_height()
            
            # 设置结果窗口的位置（在选择框下方），减小结果窗口高度
            result_height = int(height * 0.8)  
            self.result_window.geometry(f"{width}x{result_height}+{x}+{y+height+5}")

    def create_region_window(self, x, y, width, height):
        # 创建选择框窗口
        if self.region_window:
            self.region_window.destroy()
            
        self.region_window = tk.Toplevel(self.root)
        self.region_window.overrideredirect(True)  # 无边框窗口
        self.region_window.attributes('-alpha', 0.3)  # 降低透明度
        self.region_window.attributes('-topmost', True)  # 窗口置顶
        self.region_window.attributes('-toolwindow', True)  # 设置为工具窗口
        
        # 设置窗口背景色
        self.region_window.configure(bg='#2D2D2D')
        
        # 创建边框
        self.region_canvas = tk.Canvas(self.region_window, 
                         highlightthickness=0, 
                         bg='#2D2D2D')
        self.region_canvas.pack(fill='both', expand=True)
        self.update_region_rectangle(width, height)
        
        # 设置窗口位置和大小
        self.region_window.geometry(f"{width}x{height}+{x}+{y}")
        
        # 添加拖动功能
        self.region_canvas.bind('<Button-1>', self.start_move)
        self.region_canvas.bind('<B1-Motion>', self.on_move)

        # 添加调整大小的边框
        border_size = 5
        
        # 创建边框（使用深色以适应透明背景）
        right_border = tk.Frame(self.region_window, bg='#FF0000', cursor='sb_h_double_arrow', width=border_size)
        bottom_border = tk.Frame(self.region_window, bg='#FF0000', cursor='sb_v_double_arrow', height=border_size)
        corner = tk.Frame(self.region_window, bg='#FF0000', cursor='sizing', width=border_size, height=border_size)
        
        right_border.place(relx=1, rely=0, relheight=1, anchor='ne')
        bottom_border.place(relx=0, rely=1, relwidth=1, anchor='sw')
        corner.place(relx=1, rely=1, anchor='se')
        
        # 绑定大小调整事件
        for widget in [right_border, bottom_border, corner]:
            widget.bind('<Button-1>', self.start_resize_region)
            widget.bind('<B1-Motion>', self.do_resize_region)
        
        # 创建翻译结果窗口
        self.create_result_window(x, y + height + 2, width)
        
        # 确保选择框窗口在最顶层
        self.region_window.lift()

    def update_region_rectangle(self, width, height):
        # 清除之前的矩形
        self.region_canvas.delete('all')
        # 画新的矩形
        self.region_canvas.create_rectangle(2, 2, width-2, height-2, 
                                   outline='#FF0000',  # 红色边框
                                   width=2)

    def start_resize_region(self, event):
        self.start_x = event.x_root
        self.start_y = event.y_root
        self.start_width = self.region_window.winfo_width()
        self.start_height = self.region_window.winfo_height()
        
    def do_resize_region(self, event):
        if not hasattr(self, 'start_width'):
            return
            
        dx = event.x_root - self.start_x
        dy = event.y_root - self.start_y
        
        # 根据拖动的边缘调整窗口大小
        new_width = self.start_width
        new_height = self.start_height
        
        if event.widget.cget('cursor') == 'sb_h_double_arrow':
            new_width += dx
        elif event.widget.cget('cursor') == 'sb_v_double_arrow':
            new_height += dy
        elif event.widget.cget('cursor') == 'sizing':
            new_width += dx
            new_height += dy
            
        # 限制最小尺寸
        new_width = max(50, new_width)
        new_height = max(20, new_height)
        
        # 更新窗口大小
        x = self.region_window.winfo_x()
        y = self.region_window.winfo_y()
        self.region_window.geometry(f"{new_width}x{new_height}+{x}+{y}")
        
        # 更新矩形显示
        self.update_region_rectangle(new_width, new_height)
        
        # 更新监控区域
        self.monitor_region = (x, y, new_width, new_height)
        
        # 更新翻译结果窗口位置和大小
        self.update_result_window_position()

    def start_move(self, event):
        self.start_x = event.x
        self.start_y = event.y
        
    def on_move(self, event):
        if self.start_x is not None and self.region_window:
            # 计算移动距离
            dx = event.x - self.start_x
            dy = event.y - self.start_y
            
            # 获取当前窗口位置
            x = self.region_window.winfo_x() + dx
            y = self.region_window.winfo_y() + dy
            
            # 更新窗口位置
            self.region_window.geometry(f"+{x}+{y}")
            
            # 更新监控区域
            self.monitor_region = (x, y, self.monitor_region[2], self.monitor_region[3])
            
            # 更新翻译结果窗口位置
            self.update_result_window_position()

    def start_capture(self):
        # 销毁之前的窗口
        if self.region_window:
            self.region_window.destroy()
            self.region_window = None
        if self.result_window:
            self.result_window.destroy()
            self.result_window = None
            
        # 停止之前的监控
        self.stop_monitoring()
        
        # 重新注册快捷键
        self.register_hotkey()
        
        # 重置选择状态
        self.start_x = None
        self.start_y = None
        self.current_rect = None
        self.monitor_region = None
        
        # 重置canvas
        if hasattr(self, 'canvas'):
            del self.canvas
        
        # 创建全屏透明窗口用于选择区域
        self.selection_window = tk.Toplevel(self.root)
        self.selection_window.attributes('-alpha', 0.1)
        self.selection_window.attributes('-fullscreen', True)
        self.selection_window.attributes('-topmost', True)
        
        # 创建新的canvas
        self.canvas = tk.Canvas(self.selection_window, highlightthickness=0)
        self.canvas.pack(fill='both', expand=True)
        
        # 设置鼠标事件
        self.selection_window.bind('<Button-1>', self.on_mouse_down)
        self.selection_window.bind('<B1-Motion>', self.on_mouse_move)
        self.selection_window.bind('<ButtonRelease-1>', self.on_mouse_up)

    def on_mouse_down(self, event):
        self.start_x = event.x
        self.start_y = event.y
        # 清除之前的矩形
        self.canvas.delete('all')
        
    def on_mouse_move(self, event):
        if self.start_x is not None and self.start_y is not None:
            # 清除之前的矩形
            self.canvas.delete('all')
            
            # 画新的矩形
            x1, y1 = min(self.start_x, event.x), min(self.start_y, event.y)
            x2, y2 = max(self.start_x, event.x), max(self.start_y, event.y)
            self.current_rect = self.canvas.create_rectangle(
                x1, y1, x2, y2, 
                outline='red',
                width=2
            )
    
    def on_mouse_up(self, event):
        """鼠标释放时的处理"""
        if self.start_x is not None and self.start_y is not None:
            # 计算选择区域
            x1, x2 = min(self.start_x, event.x), max(self.start_x, event.x)
            y1, y2 = min(self.start_y, event.y), max(self.start_y, event.y)
            width = x2 - x1
            height = y2 - y1
            
            # 如果选择的区域太小，则忽略
            if width < 10 or height < 10:
                self.selection_window.destroy()
                self.root.deiconify()
                return
                
            # 获取相对于屏幕的坐标
            screen_x = self.selection_window.winfo_x() + x1
            screen_y = self.selection_window.winfo_y() + y1
            
            # 销毁选择窗口
            self.selection_window.destroy()
            
            # 显示主窗口
            self.root.deiconify()
            
            # 创建选择框窗口
            self.create_region_window(screen_x, screen_y, width, height)
            
            # 设置监控区域
            self.monitor_region = (screen_x, screen_y, width, height)
            
            # 开始监控
            self.monitoring = True
            self.realtime_active = True
            
            # 启动新的监控线程
            if self.monitor_thread and self.monitor_thread.is_alive():
                self.monitor_thread.join(timeout=1.0)
            self.monitor_thread = threading.Thread(target=self.realtime_monitor)
            self.monitor_thread.daemon = True
            self.monitor_thread.start()

    def stop_monitoring(self):
        """停止监控"""
        self.monitoring = False
        self.realtime_active = False
        
        # 等待监控线程结束
        if self.monitor_thread and self.monitor_thread.is_alive():
            self.monitor_thread.join(timeout=1.0)  # 等待最多1秒
            
        # 移除快捷键
        self.unregister_hotkey()
        
        # 清理窗口
        if self.region_window:
            self.region_window.destroy()
            self.region_window = None
        if self.result_window:
            self.result_window.destroy()
            self.result_window = None
            
    def toggle_realtime(self):
        if self.realtime_var.get() and self.monitor_region:
            self.realtime_active = True
            if not self.monitor_thread or not self.monitor_thread.is_alive():
                self.monitor_thread = threading.Thread(target=self.realtime_monitor)
                self.monitor_thread.daemon = True
                self.monitor_thread.start()
        else:
            self.realtime_active = False
            if self.monitor_thread and self.monitor_thread.is_alive():
                self.monitor_thread = None

    def realtime_monitor(self):
        while self.realtime_active and self.monitor_region:
            try:
                current_time = time.time()
                # 控制翻译频率
                if current_time - self.last_translation_time >= self.min_translation_interval:
                    self.translate_region()
                    self.last_translation_time = current_time
            except Exception as e:
                print(f"实时翻译错误: {str(e)}")
            time.sleep(1.0)  # 减少检查间隔，提高响应速度

    def translate_text(self, text, to_lang):
        """翻译文本，支持多个翻译服务"""
        if not text:
            return ""
            
        try:
            if self.translation_service == 'mymemory':
                translator = Translator(to_lang=to_lang)
                result = translator.translate(text)
                self.translation_error_count = 0
                return result
            elif self.translation_service == 'baidu':
                if not self.baidu_appid or not self.baidu_secretkey:
                    return "请先设置百度翻译API参数"
                    
                salt = str(random.randint(32768, 65536))
                sign = hashlib.md5((self.baidu_appid + text + salt + self.baidu_secretkey).encode()).hexdigest()
                
                url = 'https://fanyi-api.baidu.com/api/trans/vip/translate'
                params = {
                    'q': text,
                    'from': 'auto',
                    'to': 'zh',
                    'appid': self.baidu_appid,
                    'salt': salt,
                    'sign': sign
                }
                
                response = requests.get(url, params=params)
                result = response.json()
                
                if 'error_code' in result:
                    error_msg = result.get('error_msg', '未知错误')
                    if error_msg == 'Invalid Access Limit':
                        self.translation_service = 'google'
                        self.service_var.set('google')
                        messagebox.showwarning("提示", "百度翻译API访问次数超限，已切换至Google翻译")
                        return self.translate_text(text, to_lang)
                    return f"翻译错误: {error_msg}"
                    
                return result['trans_result'][0]['dst']
            else:
                url = "https://translate.googleapis.com/translate_a/single"
                params = {
                    "client": "gtx",
                    "sl": "auto",
                    "tl": to_lang,
                    "dt": "t",
                    "q": text
                }
                response = requests.get(url, params=params)
                result = response.json()[0][0][0]
                self.translation_error_count = 0
                return result
                
        except Exception as e:
            self.translation_error_count += 1
            error_msg = str(e)
            
            if "MYMEMORY WARNING" in error_msg and self.translation_service == 'mymemory':
                self.translation_service = 'google'
                self.service_var.set('google')
                return self.translate_text(text, to_lang)
                
            if self.translation_error_count >= self.max_error_count:
                old_service = self.translation_service
                if old_service == 'baidu':
                    self.translation_service = 'google'
                elif old_service == 'google':
                    self.translation_service = 'mymemory'
                else:
                    self.translation_service = 'google'
                    
                self.service_var.set(self.translation_service)
                self.translation_error_count = 0
                messagebox.showwarning("提示", f"{old_service}翻译服务出现错误，已切换至{self.translation_service}翻译")
                return self.translate_text(text, to_lang)
                
            return f"翻译错误: {error_msg}"

    def translate_region(self):
        if not self.monitor_region:
            return
            
        try:
            screenshot = pyautogui.screenshot(region=self.monitor_region)
            
            current_hash = self.get_image_hash(screenshot)
            
            if current_hash == self.last_ocr_hash:
                return
                
            self.last_ocr_hash = current_hash
            
            processed_image = self.preprocess_image(screenshot)
            
            text = pytesseract.image_to_string(processed_image, config=self.custom_config)
            text = text.strip()
            
            if self.realtime_var.get() and text == self.last_text:
                return
                
            self.last_text = text
            
            if text:
                cache_key = f"{text}_{self.lang_var.get()}"
                if cache_key in self.translation_cache:
                    translated = self.translation_cache[cache_key]
                else:
                    translated = self.translate_text(text, self.lang_var.get())
                    if len(self.translation_cache) >= self.max_cache_size:
                        self.translation_cache.pop(next(iter(self.translation_cache)))
                    self.translation_cache[cache_key] = translated
                
                if self.result_window:
                    print(f"翻译结果：{translated}")
                    self.translated_label.config(text=f"{translated}")
                    self.update_result_window_size()
            else:
                if self.result_window:
                    self.translated_label.config(text="未能识别到文字")
        except Exception as e:
            if self.result_window:
                self.translated_label.config(text=f"错误: {str(e)}")

    def preprocess_image(self, image):
        img_cv = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
        
        gray = cv2.cvtColor(img_cv, cv2.COLOR_BGR2GRAY)
        
        binary = cv2.adaptiveThreshold(
            gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, 
            cv2.THRESH_BINARY, 11, 2
        )
        
        denoised = cv2.fastNlMeansDenoising(binary)
        
        kernel = np.array([[-1,-1,-1],
                         [-1, 9,-1],
                         [-1,-1,-1]])
        sharpened = cv2.filter2D(denoised, -1, kernel)
        
        return sharpened

    def get_image_hash(self, image):
        return hashlib.md5(np.array(image).tobytes()).hexdigest()

    def create_menu(self):
        """创建菜单栏"""
        menubar = tk.Menu(self.root)
        self.root.config(menu=menubar)
        
        file_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="文件", menu=file_menu)
        file_menu.add_command(label="开始截图", command=self.start_capture)
        file_menu.add_separator()
        file_menu.add_command(label="退出", command=self.root.quit)
        
        settings_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="设置", menu=settings_menu)
        
        translate_service_menu = tk.Menu(settings_menu, tearoff=0)
        settings_menu.add_cascade(label="翻译服务", menu=translate_service_menu)
        
        translate_service_menu.add_radiobutton(
            label="MyMemory API", 
            variable=self.service_var, 
            value="mymemory",
            command=self.change_translation_service
        )
        translate_service_menu.add_radiobutton(
            label="Google Translate", 
            variable=self.service_var, 
            value="google",
            command=self.change_translation_service
        )
        translate_service_menu.add_radiobutton(
            label="百度翻译", 
            variable=self.service_var, 
            value="baidu",
            command=self.change_translation_service
        )
        translate_service_menu.add_separator()
        translate_service_menu.add_command(
            label="设置百度翻译参数", 
            command=self.set_baidu_params
        )
        
        ocr_menu = tk.Menu(settings_menu, tearoff=0)
        settings_menu.add_cascade(label="OCR设置", menu=ocr_menu)
        
        ocr_menu.add_radiobutton(
            label="自动页面分割（默认）", 
            variable=self.psm_var, 
            value=6,
            command=self.update_ocr_config
        )
        ocr_menu.add_radiobutton(
            label="单行文本", 
            variable=self.psm_var, 
            value=7,
            command=self.update_ocr_config
        )
        ocr_menu.add_radiobutton(
            label="单词文本", 
            variable=self.psm_var, 
            value=8,
            command=self.update_ocr_config
        )
        
        settings_menu.add_separator()
        settings_menu.add_command(
            label="检测间隔设置",
            command=self.set_interval
        )
        settings_menu.add_checkbutton(
            label="自动复制翻译结果", 
            variable=self.autocopy_var,
            command=self.toggle_autocopy
        )
        settings_menu.add_checkbutton(
            label="窗口置顶", 
            variable=self.topmost_var,
            command=self.toggle_topmost
        )
        
        help_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="帮助", menu=help_menu)
        help_menu.add_command(label="使用说明", command=self.show_help)
        help_menu.add_command(label="关于", command=self.show_about)

    def change_translation_service(self):
        """切换翻译服务"""
        new_service = self.service_var.get()
        
        # 如果切换到百度翻译，检查是否有配置参数
        if new_service == 'baidu' and (not self.baidu_appid or not self.baidu_secretkey):
            if messagebox.askyesno("提示", "使用百度翻译需要配置API参数，是否现在配置？"):
                self.set_baidu_params()
                # 如果用户取消配置或配置失败，回退到之前的服务
                if not self.baidu_appid or not self.baidu_secretkey:
                    self.service_var.set(self.translation_service)
                    return
            else:
                # 用户选择不配置，回退到之前的服务
                self.service_var.set(self.translation_service)
                return
        
        self.translation_service = new_service
        self.save_config()
        messagebox.showinfo("提示", f"已切换到{new_service}翻译服务")

    def update_ocr_config(self):
        """更新OCR配置"""
        psm = self.psm_var.get()
        self.custom_config = f'--oem 1 --psm {psm}'
        self.save_config()

    def toggle_autocopy(self):
        """切换自动复制状态"""
        self.save_config()

    def toggle_topmost(self):
        """切换窗口置顶状态"""
        self.root.wm_attributes('-topmost', self.topmost_var.get())
        self.save_config()

    def show_help(self):
        """显示帮助信息"""
        help_text = """使用说明：
1. 点击"开始截图"按钮选择要翻译的区域
2. 拖动选择框边缘可以调整区域大小
3. 实时翻译模式下会自动翻译区域内的文字
4. 关闭实时翻译后，使用Ctrl+Shift+/手动触发翻译
5. 在设置菜单中可以：
   - 切换翻译服务
   - 调整OCR识别模式
   - 设置自动复制和窗口置顶
"""
        messagebox.showinfo("使用说明", help_text)

    def show_about(self):
        """显示关于信息"""
        about_text = """屏幕翻译工具 v1.0
        
支持实时翻译屏幕上的文字
支持多种翻译服务和OCR设置

作者：YuKalix"""
        messagebox.showinfo("关于", about_text)

    def set_baidu_params(self):
        """设置百度翻译API参数"""
        params_window = tk.Toplevel(self.root)
        params_window.title("百度翻译API参数设置")
        params_window.geometry("300x150")
        params_window.resizable(False, False)
        
        frame = ttk.Frame(params_window, padding="10")
        frame.pack(fill='both', expand=True)
        
        ttk.Label(frame, text="APP ID:").grid(row=0, column=0, sticky='w', pady=5)
        appid_entry = ttk.Entry(frame, width=30)
        appid_entry.grid(row=0, column=1, pady=5)
        appid_entry.insert(0, self.baidu_appid)
        
        ttk.Label(frame, text="密钥:").grid(row=1, column=0, sticky='w', pady=5)
        secret_entry = ttk.Entry(frame, width=30)
        secret_entry.grid(row=1, column=1, pady=5)
        secret_entry.insert(0, self.baidu_secretkey)
        
        def save_params():
            self.baidu_appid = appid_entry.get().strip()
            self.baidu_secretkey = secret_entry.get().strip()
            if self.baidu_appid and self.baidu_secretkey:
                self.save_config()  # 保存到配置文件
                messagebox.showinfo("成功", "百度翻译API参数已保存")
                params_window.destroy()
            else:
                messagebox.showerror("错误", "APP ID和密钥不能为空")
        
        ttk.Button(frame, text="保存", command=save_params).grid(row=2, column=0, columnspan=2, pady=10)

    def set_interval(self):
        """设置检测间隔"""
        interval_window = tk.Toplevel(self.root)
        interval_window.title("检测间隔设置")
        interval_window.geometry("300x120")
        interval_window.resizable(False, False)
        
        frame = ttk.Frame(interval_window, padding="10")
        frame.pack(fill='both', expand=True)
        
        ttk.Label(frame, text="检测间隔(秒):").grid(row=0, column=0, sticky='w', pady=5)
        interval_entry = ttk.Entry(frame, width=10)
        interval_entry.grid(row=0, column=1, pady=5)
        interval_entry.insert(0, self.interval_var.get())
        
        def save_interval():
            try:
                interval = float(interval_entry.get())
                if interval < 0.1:
                    messagebox.showerror("错误", "间隔不能小于0.1秒")
                    return
                self.interval_var.set(str(interval))
                self.min_translation_interval = interval
                self.save_config()
                interval_window.destroy()
                messagebox.showinfo("成功", f"检测间隔已设置为{interval}秒")
            except ValueError:
                messagebox.showerror("错误", "请输入有效的数字")
        
        ttk.Button(frame, text="保存", command=save_interval).grid(row=1, column=0, columnspan=2, pady=10)

    def run(self):
        try:
            self.root.mainloop()
        finally:
            self.stop_monitoring()  

if __name__ == "__main__":
    app = ScreenTranslator()
    app.run()
